---
title: Typescript
description: Annotated typescript
layout: PreviewAndImplementation
---

## !demo

Include Typescript compiler's information in your code blocks using [Typescript Twoslash](https://twoslash.netlify.app/).

<Demo name="twoslash" />

## !implementation

We use the [twoslash](https://twoslash.netlify.app/) library to extract the typescript compiler's information from the code block. For more information, check the [twoslash docs](https://twoslash.netlify.app/guide/).

```bash -c
npm i twoslash
```

In the `Code` component we run typescript and transform twoslash queries and hovers into Code Hike annotations, that then use handlers similar to [Callout](/docs/code/callout) and [Tooltip](/docs/code/tooltip).

```tsx code.tsx -c
import { RawCode, Pre, highlight, AnnotationHandler } from "codehike/code"
import { createTwoslasher } from "twoslash"
// !fold[/className="(.*?)"/gm]

const twoslasher = createTwoslasher({
  fsMap: new Map(),
  compilerOptions: {},
})

async function Code({ codeblock }: { codeblock: RawCode }) {
  // run typescript:
  const { hovers, code, queries, errors } = twoslasher(
    codeblock.value,
    codeblock.lang,
  )
  // highlight code:
  const highlighted = await highlight(
    { ...codeblock, value: code },
    "github-dark",
  )

  hovers.forEach(({ text, line, character, length }) => {
    highlighted.annotations.push({
      name: "tooltip",
      query: text,
      lineNumber: line + 1,
      fromColumn: character + 1,
      toColumn: character + length,
    })
  })

  queries.forEach(({ text, line, character }) => {
    highlighted.annotations.push({
      name: "callout",
      query: text,
      fromLineNumber: line + 1,
      toLineNumber: line + 1,
      data: { character },
    })
  })

  errors.forEach(({ text, line, character }) => {
    highlighted.annotations.push({
      name: "callout",
      query: text,
      fromLineNumber: line + 1,
      toLineNumber: line + 1,
      data: { character, className: "text-red-400" },
    })
  })

  return (
    <Pre
      className="m-0 bg-zinc-950"
      code={highlighted}
      handlers={[tooltip, callout]}
    />
  )
}

import {
  TooltipProvider,
  Tooltip,
  TooltipTrigger,
  TooltipContent,
  TooltipArrow,
} from "@/components/ui/tooltip"

const tooltip: AnnotationHandler = {
  name: "tooltip",
  Inline: async ({ children, annotation }) => {
    const { query, data } = annotation
    const highlighted = await highlight(
      { value: query, lang: "ts", meta: "" },
      "github-dark",
    )
    return (
      <TooltipProvider delayDuration={300}>
        <Tooltip>
          <TooltipTrigger className="underline decoration-dashed cursor-pointer">
            {children}
          </TooltipTrigger>
          <TooltipContent className="bg-zinc-900" sideOffset={0}>
            <Pre code={highlighted} className="m-0 p-1 bg-transparent" />
            <TooltipArrow className="fill-zinc-800" />
          </TooltipContent>
        </Tooltip>
      </TooltipProvider>
    )
  },
}

const callout: AnnotationHandler = {
  name: "callout",
  Block: ({ annotation, children }) => {
    const { character, className } = annotation.data
    return (
      <>
        {children}
        <div
          style={{ minWidth: `${character + 4}ch` }}
          className={
            "w-fit border bg-zinc-900 border-current rounded px-2 relative -ml-[1ch] mt-1 whitespace-break-spaces" +
            " " +
            className
          }
        >
          <div
            style={{ left: `${character + 1}ch` }}
            className="absolute border-l border-t border-current w-2 h-2 rotate-45 -translate-y-1/2 -top-[1px] bg-zinc-900"
          />
          {annotation.query}
        </div>
      </>
    )
  },
}
```
